#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>

using std::cout;
using std::endl;
using std::string;

//对于ubuntu18.04.1而言，string，所有的拷贝、赋值，都是新开辟的
//
//string、char *、arr[]的区别：
//1、string str，str有自己的地址(栈区)，hello也有地址(sso)，
//              短的和string放一起，长的放在堆区有string的_pstr指针指过去
//2、char *a，a有自己的地址(栈区)，hello有自己的地址(文字常量区)
//3、arr[10]，  arr和hello是一体的
//4、sizeof得到整体的大小
//5、strlen、strcpy、strcat都是针对c风格的，其中strlen和strcat会去掉\0

void test(){
    int *pint=new int(10);

    string s1("hello");
    string s2("helloworldwuhan");
    string s3("welcometowuhanwangdao");
    //字符串长度小于16，位于栈
    //      大于等于16，位于堆，由指针找到

    printf("%p\n",s1.c_str());  //位于栈，直接和整个string对象放在了一起
    printf("%p\n",s2.c_str());
    printf("%p\n",s3.c_str());  //位于堆，因为它是由_pstr指针找过去的
    
    cout<<endl;
    cout<<&s1<<endl;    //s1有自己的地址，它的hello也有自己的地址
    printf("%p\n",&s1);
    cout<<&s3<<endl;    //不管怎么说，s3本身也是一个堆对象，还是位于栈

    cout<<endl;
    printf("%p\n",&pint);   //指针是栈地址，new出来的那块是堆地址
    printf("%p\n",pint);

    cout<<endl;
    cout<<sizeof(s1)<<endl; //32    sso，它的区域就是这么大
    cout<<sizeof(s3)<<endl; //32
    cout<<strlen(s1.c_str())<<endl;//5
    cout<<strlen(s3.c_str())<<endl;//21 strlen不包括\0

    delete pint;
    pint=nullptr;
}

void test2(){
    string s1="hello";
    string s2(s1);

    cout<<s1<<endl;
    cout<<s2<<endl;

    cout<<endl;
    cout<<&s1<<endl;
    printf("%p\n",&s1);
    printf("%p\n",s1.c_str());
    cout<<&s2<<endl;
    printf("%p\n",&s2);
    printf("%p\n",s2.c_str()); //和s1不一样，说明s2指向的hello是新开辟的

    cout<<endl;
    printf("%s\n",s2.c_str());
    cout<<s1.c_str()<<endl;
    cout<<s2.c_str()<<endl;

    cout<<endl;
    string s3="worldworldworldworld";
    cout<<&s3<<endl;
    printf("%p\n",s3.c_str());
    
    cout<<endl;
    s3=s1;
    printf("%p\n",s3.c_str()); //和上面一样，说明s3"指向"的字段地址没变，只是字段内容变了
    s3[0]='H';
    printf("%p\n",s1.c_str());
    printf("%p\n",s2.c_str());
    printf("%p\n",s3.c_str());
    
}

int main()
{   
    test();
    return 0;
}

